using System;
using Godot;

public partial class GravityGun : Node2D
{
    [ExportGroup("Settings")]
    [Export] public float MaxDistance = 300.0f;     // 最大抓取距离
    [Export] public float GrabStrength = 5.0f;     // 抓取力度 (越大越跟手，越小越笨重)
    [Export] public float ThrowForce = 100.0f;     // 右键松开时的投掷力度
    [Export] public float RotationalDrag = 0.1f;    // 旋转阻尼 (防止箱子疯狂旋转)
    [Export] public float MaxSpeed = 200.0f;      // 抓取的物体最大速度限制

    [ExportGroup("Refs")]
    [Export] public RayCast2D RayCast;
    [Export] public Line2D BeamVisual; // 牵引线视觉

    private RigidBody2D _grabbedBody;
    private PlayerController _playerRef; // 引用玩家以处理碰撞排除

    public override void _Ready()
    {
        // 获取玩家引用 (假设 GravityGun 是 Player 的子孙节点)
        // 向上查找直到找到 PlayerController
        Node parent = GetParent();
        while (parent != null)
        {
            if (parent is PlayerController p)
            {
                _playerRef = p;
                break;
            }
            parent = parent.GetParent();
        }

        if (BeamVisual != null) BeamVisual.Visible = false;
    }

    public override void _PhysicsProcess(double delta)
    {
        // 1. 让 RayCast 始终指向鼠标 (即便枪本身在旋转，RayCast 也要对准鼠标点击位置)
        // 注意：如果你把这个节点放在了已经跟随鼠标旋转的 GunPivot 下，
        // 那么 RayCast 的 TargetPosition 只需要设为 X轴长度即可。
        // 这里假设它挂在 GunPivot 下：

        // 2. 输入处理
        if (Input.IsActionJustPressed("fire_b")) // 鼠标右键按下：尝试抓取
        {
            GD.Print("尝试抓取物体");
            TryGrab();
            AudioManager.Instance.PlaySfx("res://assets/cc0_sound_effects/grab.wav", -5f, 1.0f);
        }
        else if (Input.IsActionJustReleased("fire_b")) // 鼠标右键松开：投掷/放下
        {
            GD.Print("投掷或放下物体");
            ThrowOrDrop();
        }

        // 3. 持续牵引逻辑
        if (_grabbedBody != null)
        {
            UpdateHoldPhysics((float)delta);
            UpdateVisuals();
        }
        else
        {
            if (BeamVisual != null) BeamVisual.Visible = false;
        }
    }

    private void TryGrab()
    {
        if (_grabbedBody != null) return; // 已经手里有东西了

        // 更新射线的检测点为鼠标位置 (限制在最大距离内)
        Vector2 mousePos = GetGlobalMousePosition();
        Vector2 dir = (mousePos - GlobalPosition).Normalized();
        float dist = GlobalPosition.DistanceTo(mousePos);

        // 限制射线长度
        RayCast.TargetPosition = Vector2.Right * Mathf.Min(dist, MaxDistance);
        RayCast.ForceRaycastUpdate();

        if (RayCast.IsColliding())
        {
            var collider = RayCast.GetCollider();

            // 检查是不是 ChromaBox (或者任何 RigidBody)
            if (collider is ChromaBox box)
            {
                // 1. 锁定对象
                _grabbedBody = box;

                // 2. 禁用与玩家的碰撞 (防止把自己挤飞)
                if (_playerRef != null)
                {
                    _grabbedBody.AddCollisionExceptionWith(_playerRef);
                }

                // 3. 唤醒刚体 (防止它处于休眠状态)
                _grabbedBody.Freeze = false; // 确保如果是可推箱子，它被解冻了
                _grabbedBody.Sleeping = false;

                // 可选：稍微抬高一点防止卡在地里
                _grabbedBody.ApplyCentralImpulse(Vector2.Up * 100);
            }
        }
    }

    private void ThrowOrDrop()
    {
        if (_grabbedBody == null) return;

        // 1. 恢复与玩家的碰撞
        if (_playerRef != null)
        {
            _grabbedBody.RemoveCollisionExceptionWith(_playerRef);
        }

        // 2. 施加投掷力 (朝鼠标方向)
        Vector2 throwDir = (GetGlobalMousePosition() - GlobalPosition).Normalized();
        _grabbedBody.ApplyCentralImpulse(throwDir * ThrowForce);

        // 3. 释放引用
        _grabbedBody = null;
        if (BeamVisual != null) BeamVisual.Visible = false;
    }

    private void UpdateHoldPhysics(float dt)
    {
        // 如果箱子被删了（比如掉进坑里销毁了），重置状态
        if (!GodotObject.IsInstanceValid(_grabbedBody))
        {
            _grabbedBody = null;
            return;
        }

        // --- 核心物理：GMod 重力枪手感 ---

        // 目标位置：鼠标位置
        Vector2 targetPos = GetGlobalMousePosition();

        // 限制：不能把箱子拉得离玩家太远 (限制在 MaxDistance 范围内)
        // 这样可以防止玩家把箱子瞬移到屏幕另一端穿墙
        float distToPlayer = GlobalPosition.DistanceTo(targetPos);
        if (distToPlayer > MaxDistance)
        {
            Vector2 dir = (targetPos - GlobalPosition).Normalized();
            targetPos = GlobalPosition + dir * MaxDistance;
        }

        // 计算 当前位置 -> 目标位置 的向量
        Vector2 diff = targetPos - _grabbedBody.GlobalPosition;

        // 1. 线性速度控制 (Linear Velocity)
        // 我们不使用 AddForce，而是直接修改 Velocity 来获得更强的控制力，
        // 同时保留物理引擎的碰撞计算。
        // 公式：速度 = 距离 * 强度 (这其实是一个 P-Controller)
        _grabbedBody.LinearVelocity = Mathf.Min(diff.Length() * GrabStrength, MaxSpeed) * diff.Normalized();

        // 2. 角度稳定 (Angular Damp)
        // 让箱子慢慢转正，或者至少不要疯狂自转
        _grabbedBody.AngularVelocity = Mathf.Lerp(_grabbedBody.AngularVelocity, 0, RotationalDrag);

        // 如果想让箱子强制保持直立 (可选)
        // float targetAngle = 0;
        // _grabbedBody.GlobalRotation = Mathf.LerpAngle(_grabbedBody.GlobalRotation, targetAngle, dt * 5f);
    }




    private void UpdateVisuals()
    {
        if (BeamVisual != null)
        {
            BeamVisual.Visible = true;
            // 线段：从枪口 -> 箱子中心
            // 需要转为局部坐标，因为 Line2D 是 GravityGun 的子节点
            BeamVisual.Points = new Vector2[]
            {
                Vector2.Zero,
                ToLocal(_grabbedBody.GlobalPosition)
            };
        }
    }
}